﻿#include<syslog.h>
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#include<stdarg.h>
#include<string.h>
 /*
  * 描述：根据pid获取进程名称
  * 参数：pid       -- 本进程的pid
  *       task_name -- 字符串，传出的进程名
  * 返回值：无
  */
void getNameByPid(pid_t pid, char* task_name);

/*
 * 描述：用于做日志录入【用户不应该调用此函数，应调用 LOG_RecordMsg()】
 * 参数：level -- 日志等级
 *       fmt   -- 字符串，用于记录情况
 * 返回值：无
 */
static void LOG_LogMsg(int level, const char* fmt, ...);

/*
 * 描述：syslog初始化函数
 * 参数：ident    -- 用户写入字符串，用于标识当前日志
 *       option   -- 建议采用“LOG_CONS | LOG_PID”
 *       facility -- 建议采用“LOG_USER”
 * 返回值：无
 */
void LOG_Init(const char* ident, int option, int facility);


/*
 * 描述：日志使用完成后记得关闭
 * 参数：无
 * 返回值：无
 */
void LOG_CloseLog();

#define LOG_TRUE 1
#define LOG_FAIL 0
#define LOG_TASKNAME_STR 10 
#define LONG_PATH_LEN   512 //路径长度
#define LOG_MAX_STR_LEN 1024 //最大日志长度
#define LOG_LEVEL_STR 30 //username + level

/*
* 日志等级（0~7）
* LOG_EMERG     系统不可用
* LOG_ALERT     消息需立即处理
* LOG_CRIT      重要情况
* LOG_ERR       错误
* LOG_WARNING   警告
* LOG_NOTICE    正常情况，但较为重要
* LOG_INFO      信息
* LOG_DEBUG     调试信息
*/

/*
 * 描述：用于做日志录入
 * 参数：level -- 日志等级
 *       fmt   -- 字符串，用于记录情况
 * 返回值：无
 */
#define LOG_RecordMsg(level, fmt, ...)\
        LOG_LogMsg(level, "%s[line:%d]: " fmt, __FUNCTION__, __LINE__, ##__VA_ARGS__);


 /*
  * 描述：根据pid获取进程名称
  * 参数：pid       -- 本进程的pid
  *       task_name -- 字符串，传出的进程名
  * 返回值：无
  */
void getNameByPid(pid_t pid, char* task_name)
{
    char proc_path[LONG_PATH_LEN];
    char buf[LONG_PATH_LEN];
    sprintf(proc_path, "/proc/%d/status", pid);
    FILE* fp = fopen(proc_path, "r");
    if (NULL != fp)
    {
        if (fgets(buf, LONG_PATH_LEN - 1, fp) == NULL)
        {
            fclose(fp);
        }
        fclose(fp);
        sscanf(buf, "%*s %s", task_name);
    }
}


/*
 * 描述：用于做日志录入【用户不应该调用此函数，应调用 LOG_RecordMsg()】
 * 参数：level -- 日志等级
 *       fmt   -- 字符串，用于记录情况
 * 返回值：无
 */
static void LOG_LogMsg(int level, const char* fmt, ...)
{
    pid_t pid;
    char taskName[LOG_TASKNAME_STR + LOG_MAX_STR_LEN + LOG_LEVEL_STR];
    char msgstr[LOG_MAX_STR_LEN+2];
    char levelstr[LOG_LEVEL_STR];
    unsigned int strlen;
    va_list ap;
    memset(msgstr, 0x00, sizeof(msgstr));

    /*获取日志等级的字符串*/
    switch (level)
    {
    case LOG_EMERG:
        strcpy(levelstr, "[EMERG]: ");
        break;
    case LOG_ALERT:
        strcpy(levelstr, "[ALERT]: ");
        break;
    case LOG_CRIT:
        strcpy(levelstr, "[CRIT]: ");
        break;
    case LOG_ERR:
        strcpy(levelstr, "[ERR]: ");
        break;
    case LOG_WARNING:
        strcpy(levelstr, "[WARNING]: ");
        break;
    case LOG_NOTICE:
        strcpy(levelstr, "[NOTICE]: ");
        break;
    case LOG_INFO:
        strcpy(levelstr, "[INFO]: ");
        break;
    case LOG_DEBUG:
        strcpy(levelstr, "[DEBUG]: ");
        break;

    default:
        perror("log level err!!!");
        break;
    }

    /*获取进程名称的字符串*/
    pid = getpid();
    getNameByPid(pid, taskName);
    
    /*将用户写入的字符串进行格式化*/
    va_start(ap, fmt);
    strlen = vsprintf(msgstr, fmt, ap);
    if (strlen >= LOG_MAX_STR_LEN)
    {
        strlen = LOG_MAX_STR_LEN;
        msgstr[strlen] = '\n';
        strlen++;
    }
    msgstr[strlen] = '\0';

    /*进行两次字符串拼接*/
    strcat(taskName, levelstr);
    strcat(taskName, msgstr);
    
    /*调用syslog函数，写入日志*/
    syslog(level, "%s", taskName);
    va_end(ap);
}

/*
 * 描述：syslog初始化函数
 * 参数：ident    -- 用户写入字符串，用于标识当前日志
 *       option   -- 建议采用“LOG_CONS | LOG_PID”
 *       facility -- 建议采用“LOG_USER”
 * 返回值：无
 */
void LOG_Init(const char* ident, int option, int facility)
{
    /*
    * 不要试图通过PID获得进程名，并将进程进程名传入 ident
    * 否则该代码会出现莫名其妙的bug
    * 并且bug现象比较随机
    */
    openlog(ident, option, facility);
    fprintf(stdout, "START LOG!!\n");
}


/*
 * 描述：日志使用完成后记得关闭
 * 参数：无
 * 返回值：无
 */
void LOG_CloseLog()
{
    closelog();
    fprintf(stdout, "CLOSE LOG!!\n");
}


/*测试程序*/
int main(int argc, char* argv[])
{
    int i = 10;
    printf("%s 向你问好!\n", "Log_syslog");
    LOG_Init("mylog", LOG_CONS | LOG_PID, LOG_USER);
    while (i--)
    {
        LOG_RecordMsg(LOG_ERR, "现在开始运行log");
        sleep(1);
    }
    LOG_CloseLog();
    return 0;
}